package org.yun.octopus.base.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.Assert;
import org.yun.octopus.base.enums.RoleType;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

import static org.yun.octopus.base.core.RollbackFactory.STEP_RESULT_MAP;
import static org.yun.octopus.base.enums.RoleType.*;

/**
 * @author liyunfeng31
 */
public class CommonUtil {


    public static final ObjectMapper MAPPER = new ObjectMapper();

    public static ThreadLocal<String> THREADLOCAL = new ThreadLocal<>();


    /**
     * json取值
     * @param obj obj
     * @param field field
     * @return val
     */
    public static JsonNode valFromObj(Object obj, String field){
        return MAPPER.valueToTree(obj).get(field);
    }



    public static <E> int drain(BlockingQueue<E> q, Collection<? super E> buffer, int numElements, long timeout, TimeUnit unit) throws InterruptedException {
        Assert.notNull(buffer,"[Assertion failed] - the buffer argument cannot be null");
        long deadline = System.nanoTime() + unit.toNanos(timeout);
        int added = 0;

        while(added < numElements) {
            added += q.drainTo(buffer, numElements - added);
            if (added < numElements) {
                E e = q.poll(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);
                if (e == null) {
                    break;
                }
                buffer.add(e);
                ++added;
            }
        }
        return added;
    }



    public static Map<Integer, Integer> initMap(int stepNo, int code){
        Map<Integer, Integer> initMap = STEP_RESULT_MAP;
        initMap.put(stepNo,code);
        return initMap;
    }


    public static Map<byte[], byte[]> intMap2BytesMap(Map<Integer, Integer> intMap){
        Map<byte[], byte[]> bytesMap = new HashMap<>(8);
        for (Map.Entry<Integer, Integer> kv : intMap.entrySet()) {
            bytesMap.put(int2Bytes(kv.getKey()), int2Bytes(kv.getValue()));
        }
        return bytesMap;
    }



    public static Map<byte[], byte[]> objMap2BytesMap(Map<String, Object> map) {
        Map<byte[], byte[]> bytesMap = new HashMap<>(8);
        for (Map.Entry<String, Object> kv : map.entrySet()) {
            bytesMap.put(kv.getKey().getBytes(), kv.getValue().toString().getBytes());
        }
        return bytesMap;
    }


    public static Map<String, Object> joinMap(int stepNo, int code, String childNo){
        Map<String, Object> map = new HashMap<>(2);
        map.put(stepNo+"No",childNo);
        map.put(stepNo+"",code);
        return map;
    }

    public static byte[] int2Bytes(int i){
        return ByteBuffer.allocate(4).putInt(i).array();
       // int result = ByteBuffer.wrap(bytes).getInt();
    }

    public static String getCtxBizNo(RoleType role, String bizNo){
        if(role == NORMAL || role == END){
            return bizNo;
        }
        if(role == PARENT){
            THREADLOCAL.set(bizNo);
            return bizNo;
        }
        String ctxBizNo = THREADLOCAL.get();
        THREADLOCAL.remove();
        return ctxBizNo;
    }
}
